package org.grottarossa.ui.core.casemanagement.tasks;



import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.SimpleDateFormat;

import java.util.ArrayList;
import java.util.Date;
import java.util.ResourceBundle;

import org.grottarossa.template.data.enums.EnumTaskType;
import org.grottarossa.template.data.pojo.Assignee;
import org.grottarossa.template.data.pojo.DeadLine;
import org.grottarossa.template.data.pojo.tasks.Task;
import org.grottarossa.template.data.pojo.tasks.TaskList;
import org.grottarossa.template.data.pojo.workflows.Workflow;
import org.grottarossa.template.drivers.DriverException;
import org.grottarossa.template.drivers.components.tokens.CaseManagementId;
import org.grottarossa.template.drivers.components.tokens.TaskManagementId;
import org.grottarossa.template.drivers.components.tokens.WorkFlowId;
import org.grottarossa.ui.core.ApplicationSession;
import org.grottarossa.ui.core.BPMResource;
import org.grottarossa.ui.core.Dialog.MessageBox;
import org.grottarossa.ui.core.Dialog.MessageBoxListener;
import org.grottarossa.ui.core.Dialog.MessageBox.ButtonType;
import org.grottarossa.ui.core.Dialog.MessageBox.Buttons;
import org.grottarossa.ui.core.base.BasePanel;
import org.grottarossa.ui.core.base.IBaseComponent;
import org.grottarossa.ui.core.casemanagement.CaseManagementPanel;
import org.grottarossa.ui.core.casemanagement.CaseTabSheet;
import org.grottarossa.ui.core.casemanagement.bpm.BaseBPMPanel;
import org.grottarossa.ui.core.casemanagement.bpm.IAction;
import org.grottarossa.ui.core.casemanagement.bpm.WorkflowStarter;
import org.grottarossa.ui.core.container.ITaskPanelAssignListener;
import org.grottarossa.ui.core.container.ITaskPanelExpireListener;
import org.grottarossa.ui.core.container.ITaskPanelSkipListener;
import org.grottarossa.ui.core.container.TaskContainer;
import org.grottarossa.ui.core.controls.deadline.DeadLineData;
import org.grottarossa.ui.core.controls.deadline.DeadLineFactory;
import org.grottarossa.ui.core.controls.deadline.IDeadLineListener;
import org.grottarossa.ui.core.controls.searchuser.ISearchUserListener;
import org.grottarossa.ui.core.controls.searchuser.SearchUser;
import org.grottarossa.ui.core.controls.searchuser.SearchUserEvent;
import org.grottarossa.ui.core.controls.searchuser.SearchUserFactory;
import org.grottarossa.ui.core.controls.skiptask.ISkipTaskListener;
import org.grottarossa.ui.core.controls.skiptask.SkipTask;
import org.grottarossa.ui.core.controls.skiptask.SkipTaskData;
import org.grottarossa.ui.core.controls.skiptask.SkipTaskFactory;
import org.grottarossa.ui.core.i18n.DM;

import com.vaadin.data.Item;
import com.vaadin.event.ItemClickEvent;
import com.vaadin.event.ItemClickEvent.ItemClickListener;
import com.vaadin.terminal.Sizeable;
import com.vaadin.ui.Button;
import com.vaadin.ui.Component;
import com.vaadin.ui.GridLayout;
import com.vaadin.ui.Panel;
import com.vaadin.ui.TreeTable;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Window;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Window.Notification;

public class TaskListPanel extends BasePanel implements ItemClickListener, MessageBoxListener, ITaskPanelSkipListener,
ISkipTaskListener, ITaskPanelAssignListener, ISearchUserListener, ITaskPanelExpireListener, IDeadLineListener
{
	private static final long serialVersionUID = 5367036209492343058L;

	/*** Referenze oggetti esterni ***/
	private final IBaseComponent m_view;
	private final CaseManagementId m_caseManagementId;
	private final CaseTabSheet m_caseTabSheet;

	/*** Variabili interne ***/
	private Task m_taskToExecute;
	private Task m_taskToModify;
	private Window m_deadlinePopup;
	private Window m_skipPopup;
	private Window m_assignPopup;

	/*** Controlli grafici ***/
	private TaskList m_taskList = null;
	private TreeTable treeTable = null;

	public TaskListPanel(ApplicationSession appSession, CaseManagementId id, IBaseComponent view, CaseTabSheet caseTabSheet)
	{
		super(appSession, DM.instance().getBundle(TaskListPanel.class.getName()));

		this.m_caseTabSheet = caseTabSheet;
		this.m_caseManagementId = id;
		this.m_view = view;

		initializeComponents();
	}

	@Override
	protected void initializeComponents()
	{
		VerticalLayout v = new VerticalLayout();
		v.setHeight(100, Sizeable.UNITS_PERCENTAGE);
		v.setWidth(100, Sizeable.UNITS_PERCENTAGE);
		setLayout(v);

		treeTable = new TreeTable();
		treeTable.setHeight(100, Sizeable.UNITS_PERCENTAGE);
		treeTable.setWidth(100, Sizeable.UNITS_PERCENTAGE);
		treeTable.setSortDisabled(true);

		reload(m_caseManagementId);

		this.setSizeFull();

		treeTable.addListener(this);
		v.addComponent(treeTable);
	}

	/***
	 * Invocato quando viene premuto il tasto di assign sulla lista dei task
	 */
	public void notifyAssignButtonClicked(Task task)
	{
		m_taskToModify = task;
		SearchUserFactory f = new SearchUserFactory(m_appSession);
		SearchUser assignPopupView = f.createUserSearcher();
		assignPopupView.addListener((ISearchUserListener)this);
		m_assignPopup = m_view.showInPopup(assignPopupView, 640, 480, "", true, true);
	}

	/***
	 * Invocato quando viene premuto il tasto di skip sulla lista dei task
	 */
	public void notifySkipButtonClicked(Task task)
	{
		m_taskToModify = task;
		SkipTaskFactory stf = new SkipTaskFactory(m_appSession);
		SkipTask skipPopupView = stf.createSkipTask(task);
		skipPopupView.addListener((ISkipTaskListener)this);
		m_skipPopup = m_view.showInPopup(skipPopupView, 640, 200, "", true, true);
	}

	/***
	 * Invocato quando viene premuto il tasto di expire sulla lista dei task
	 */
	public void notifyExpireButtonClicked(Task task)
	{
		m_taskToModify = task;
		DeadLineFactory f = new DeadLineFactory(m_appSession);
		org.grottarossa.ui.core.controls.deadline.DeadLine deadlinePopupView = f.createDeadLine();
		deadlinePopupView.addListener((IDeadLineListener)this);
		m_deadlinePopup = m_view.showInPopup(deadlinePopupView, 640, 200, "", true, true);
	}

	/***
	 * Invocato quando si conferma la selezione della nuova data di scadenza sul popup
	 */
	public void ok(DeadLineData event)
	{
		try
		{
			if( event.getType().getValue() == 0)
				m_taskToModify.setDeadLine(null);
			else
				m_taskToModify.setDeadLine(new DeadLine(event.getData(), event.getData()));

			m_appSession.getBuilder().getCaseManagement().updateTask(m_taskToModify);
		}
		catch(Exception ex)
		{
			ex.printStackTrace();
			getWindow().showNotification(m_localizer.getString("notify.updatetaskko"), Notification.TYPE_ERROR_MESSAGE);
		}

		m_view.removePopup(m_deadlinePopup);
		m_caseTabSheet.refresh();
		m_taskToModify = null;
	}

	/***
	 * Invocato quando il task � stato skippato
	 */
	public void ok(SkipTaskData event)
	{
		m_view.removePopup(m_skipPopup);
		m_caseTabSheet.refresh();
		m_taskToModify = null;
	}

	/***
	 * Invocato quando l'utente/ruolo � stato assegnato al task
	 */
	public void ok(SearchUserEvent event)
	{
		try
		{
			Assignee a;

			if(event.isUser())
				a = new Assignee(event.getUser().getDisplayName(), event.getUser().getLoginID());
			else
				a = new Assignee(event.getSelected(), event.getSelected());

			m_taskToModify.setAssignee(a);
			m_appSession.getBuilder().getCaseManagement().updateTask(m_taskToModify);
		}
		catch(Exception ex)
		{
			ex.printStackTrace();
			getWindow().showNotification(m_localizer.getString("notify.updatetaskko"), Notification.TYPE_ERROR_MESSAGE);
		}

		m_view.removePopup(m_assignPopup);
		m_caseTabSheet.refresh();
		m_taskToModify = null;
	}

	/***
	 * Invocato quando viene premuto cancel su un popup
	 */
	public void cancel()
	{
		m_view.removePopup(m_deadlinePopup);
		m_view.removePopup(m_skipPopup);
		m_view.removePopup(m_assignPopup);
	}

	public void reload(CaseManagementId id)
	{
		try
		{
			m_taskList = m_appSession.getBuilder().getCaseManagement().getTaskList(id);
		}
		catch (DriverException e)
		{
			getWindow().showNotification(m_localizer.getString("panel.error") + " - " +
 					  e.getMessage(),
 					  Notification.TYPE_ERROR_MESSAGE);
		}

		TaskContainer container = new TaskContainer(m_taskList, getWindow());
		container.addListener((ITaskPanelSkipListener)this);
		container.addListener((ITaskPanelAssignListener)this);
		container.addListener((ITaskPanelExpireListener)this);

		treeTable.setContainerDataSource(container);
		treeTable.setVisibleColumns(TaskContainer.VISIBLE_COLUMNS);
		treeTable.setColumnHeaders(TaskContainer.HEADER_COLUMNS);
		treeTable.setSizeFull();
		treeTable.setColumnCollapsingAllowed(true);
		treeTable.setPageLength( container.getItemIds().size());

		for (Object obj : container.getItemIds())
		{
			Item item = container.getItem(obj);

			WorkFlowId iWorkflowID = (WorkFlowId)item.getItemProperty(TaskContainer.WORKFLOW_ID).getValue();
			EnumTaskType taskType = (EnumTaskType)item.getItemProperty(TaskContainer.TYPE).getValue();

			if ( taskType.isElement() )
			{

				if(iWorkflowID.getIdentity() instanceof String && iWorkflowID.getIdentity().equals(TaskContainer.NOP))
					treeTable.setItemIcon(obj, BPMResource.ICON_TASK_FORM);
				else if(iWorkflowID.getIdentity() instanceof Integer)
					treeTable.setItemIcon(obj, BPMResource.ICON_TASK_PROCESS);
			}
			else
				treeTable.setCollapsed(obj, false);
		}
	}

	/***
	 * Gestisce la conferma di avvio processo
	 */
	public void manageButton(ButtonType buttonType, Object object)
	{
		//Gestione avvio di un task della lista
		if ( object.getClass() == Workflow.class )
		{
			if ( buttonType == MessageBox.ButtonType.Yes )
        	{
				IAction onTaskEnd = new IAction()
				{
					public void execute()
					{
						m_caseTabSheet.refresh();
					}
				};

				ArrayList<IAction> actions = new ArrayList<IAction>();
				actions.add(onTaskEnd);

				WorkflowStarter starter = new WorkflowStarter(m_appSession, m_view, actions);

				boolean initResult;

				if(m_taskToExecute.isIstantiated())
					initResult = starter.setWorkflow((Workflow)object, m_taskToExecute.getWorkItemId());
				else
					initResult = starter.setWorkflow((Workflow)object);

				if(initResult)
					starter.start(true);
        	}
		}
	}

	/***
	 * Viene invocato quando si clicca su un'elemento della tasklist
	 */
	public void itemClick(ItemClickEvent event)
	{
		EnumTaskType taskType = (EnumTaskType)event.getItem().getItemProperty(TaskContainer.TYPE).getValue();

		if ( taskType.isElement() )
		{

			WorkFlowId iWorkflowID = (WorkFlowId)event.getItem().getItemProperty(TaskContainer.WORKFLOW_ID).getValue();

			TaskManagementId taskId = (TaskManagementId)event.getItem().getItemProperty(TaskContainer.TASK_MANAGMENT_ID).getValue();

			for(Task t : m_taskList)
			{
				if(t.getTaskID().getIdentity().equals(taskId.getIdentity()))
				{
					m_taskToExecute = t;
					break;
				}
			}

			if(iWorkflowID.getIdentity() instanceof Integer)
			{
				Integer iWorkflowVersion = (Integer)event.getItem().getItemProperty(TaskContainer.WORKFLOW_VERSION).getValue();
				String sProcessRepositoryField = (String)event.getItem().getItemProperty(TaskContainer.PROCESS_REPOSITORY_FIELD).getValue();
	        	String sProcessScriptName = (String)event.getItem().getItemProperty(TaskContainer.PROCESS_SCRIPT_NAME).getValue();
	        	String sScriptName = (String)event.getItem().getItemProperty(TaskContainer.SCRIPT).getValue();

	        	Workflow workflow = new Workflow(iWorkflowID, iWorkflowVersion);
	        	workflow.addParameter(sProcessRepositoryField, ("1."+iWorkflowID.getIdentity()+".") + this.m_caseManagementId.getIdentity());
	        	workflow.addParameter(sProcessScriptName, sScriptName);

	        	String sMessage = String.format("Eseguo processo - id:%d version:%d",((Integer)iWorkflowID.getIdentity()).intValue(), iWorkflowVersion.intValue());
	        	new MessageBox(getWindow(), "Esegui Processo", sMessage, Buttons.YesNo, this, workflow);
			}
			else if(iWorkflowID.getIdentity() instanceof String && iWorkflowID.getIdentity().equals(TaskContainer.NOP))
			{
				//Valorizzo la percentuale dell'oggetto
				String sCompito = (String)event.getItem().getItemProperty("Compito").getValue();
				int iStato = (Integer)event.getItem().getItemProperty("StatoVal").getValue();
				int iCompletato = (Integer)event.getItem().getItemProperty("Completato").getValue();

				DateFormat df = new SimpleDateFormat("dd/MM/yyyy");
				Date dtScadenza = null;

				try
				{
					dtScadenza = df.parse((String)event.getItem().getItemProperty("Scadenza").getValue());
				}
				catch (Exception e)
				{

				}

				String sAssegnatoA = (String)event.getItem().getItemProperty("Assegnato a").getValue();
				final TaskManagementId iTaskID = (TaskManagementId)event.getItem().getItemProperty("TaskId").getValue();
				final CaseManagementId iCaseFolderId = (CaseManagementId)event.getItem().getItemProperty("CaseFolderId").getValue();

				final TaskLess task = new TaskLess();
				task.setAssegnatoA(sAssegnatoA);
				task.setCompito(sCompito);
				task.setCompletato(iCompletato);
				task.setScadenza(dtScadenza);
				task.setStato(iStato);

				final TaskPanel panel = new TaskPanel(m_appSession, task);
				final Window taskFormWindow = new Window();

				GridLayout ourLayout = new GridLayout(1, 2);
				ourLayout.setMargin(true);
				ourLayout.setSpacing(true);

				ourLayout.addComponent(panel,0,0);

				Button save = new Button(m_localizer.getString("panel.taskform.save.button"), new Button.ClickListener()
				{
					public void buttonClick(ClickEvent event)
					{
						panel.getForm().commit();

						Task taskFull = new Task();
						taskFull.setAssignee(new Assignee (task.getAssegnatoA(), task.getAssegnatoA()));
						taskFull.setCompletedBy(m_appSession.getBuilder().getIdentity().getUser());
						taskFull.setDeadLine(new DeadLine(task.getScadenza(),null));
						taskFull.setModifiedBy(m_appSession.getBuilder().getIdentity().getUser());
						taskFull.setPercentCompleted(task.getCompletato());
						//taskFull.setStatus(EnumStatus.getEnumValue(task.getStato()));
						taskFull.setTaskContainerID( iCaseFolderId );
						taskFull.setTaskID( iTaskID );

						try
						{
							m_appSession.getBuilder().getCaseManagement().updateTask(taskFull);
							((Window)taskFormWindow.getParent()).removeWindow(taskFormWindow);
							reload(m_caseManagementId);
						}
						catch (NullPointerException e)
						{
							getWindow().showNotification("Errore Grave ",
                   					  Notification.TYPE_ERROR_MESSAGE);
						}
						catch (DriverException e)
						{
							getWindow().showNotification(m_localizer.getString("panel.error")+" - "+
                   					  e.getMessage(),
                   					  Notification.TYPE_ERROR_MESSAGE);
						}
					}
						});
				ourLayout.addComponent(save, 0, 1);

				taskFormWindow.setContent(ourLayout);
				taskFormWindow.setModal(true);
				taskFormWindow.setSizeUndefined();

				getWindow().addWindow(taskFormWindow);
			}
		}
	}

	public void refresh()
	{
		reload(m_caseManagementId);
	}
}
